package code.c02_list.dlinkList;

/**
 * @author thinkpad - 83start
 * @version v1.0
 * @create 2022/9/18 19:42
 * @package code.c02_list.classwork
 * @description 双链表泛型类
 */

public class DLinkListClass<E> {
    // 存放头节点
    public DLinkNode<E> dhead;


    public DLinkListClass() {
        // 创建头节点
        dhead = new DLinkNode<E>();
        dhead.prior = null;
        dhead.next = null;
    }

    // ==================================== 基本运算 =============================

    /**
     *  插入元素
     * @param i
     * @param e
     */
    public void insert(int i, E e) {
        if (i < 0 || i > size()) {
            throw new IllegalArgumentException("插入：位置i不在有效范围内。");
        }
        DLinkNode<E> s = new DLinkNode<>(e);

        DLinkNode<E> p = geti(i - 1);
        s.next = p.next;
        if (p.next != null) {
            p.next.prior = s;
        }
        p.next = s;
        s.prior = p;
    }

    /**
     * 删除元素
     * @param i
     */
    public void delete(int i) {
        if (i < 0 || i > size() - 1) {
            throw new IllegalArgumentException("删除：位置i不在有效的范围内。");
        }
        DLinkNode<E> p = geti(i);
        if (p.next != null) {
            p.next.prior = p.prior;
        }

        p.prior.next = p.next;
    }

    /**
     * 头插法建表
     * @param a
     */
    public void createListF(E[] a) {
        DLinkNode<E> s;
        for (int i = 0; i < a.length; i++) {
            s = new DLinkNode<>(a[i]);
            s.next = dhead.next;
            if (dhead.next != null) {
                dhead.next.prior = s;
            }
            dhead.next = s;
            s.prior = dhead;
        }
    }

    /**
     *  使用尾插法
     * @param a
     */
    public void createListR(E[] a) {
        DLinkNode<E> s, t;
        t = dhead;
        for (int i = 0; i < a.length; i++) {
            s = new DLinkNode<>(a[i]);
            t.next = s;
            s.prior = t;
            t = s;
        }
        t.next = null;
    }

    /**
     * geti() 获取链表种第i个元素
     * @param i
     * @return
     */
    private DLinkNode<E> geti(int i) {
        DLinkNode<E> p = dhead;
        int j = -1;
        while (j < i) {
            j++;
            p = p.next;
        }

        return p;
    }

    /**
     * add() 将元素 e 添加到线性表的末尾：Add(e)
     * @param e
     */
    public void add(E e) {
        DLinkNode<E> s = new DLinkNode<>(e);
        DLinkNode<E> p = dhead;
        while (p.next != null) {
            p = p.next;
        }
        p.next = s;
    }

    /**
     * 求线性表的长度：size()
     * @return
     */
    public int size() {
        DLinkNode<E> p = dhead;
        int cnt = 0;

        while (p.next != null) {
            cnt++;
            p = p.next;
        }

        return cnt;
    }

    /**
     * 设置线性表的长度
     * @param nlen
     */
    public void setSize(int nlen) {
        int len = size();
        if (nlen < 0 || nlen > size()) {
            throw new IllegalArgumentException("设置长度：n不在有效的范围内");
        }
        if (nlen == len) {
            return;
        }
        DLinkNode<E> p = geti(nlen - 1);
        p.next = null;
    }

    /**
     * 求线性表种序号为 i 的元素：getElem(i)
     * @param i
     * @return
     */
    public E getElem(int i) {
        int len = size();
        if (i < 0 || i > len - 1) {
            throw new IllegalArgumentException("查找：位置 i 不在有效的范围内。");
        }
        DLinkNode<E> p = geti(i);
        return (E) p.data;
    }

    /**
     * 设置线性表中序号为 i 的元素：setElem(i,e)
     * @param i
     * @param e
     */
    public void setElem(int i, E e) {
        if (i < 0 || i > size() - 1) {
            throw new IllegalArgumentException("设置：位置 i 不在有效的范围内。");
        }
        DLinkNode<E> p = geti(i);
        p.data = e;
    }

    /**
     * 求线性表中第一个值为 e 的元素的逻辑序号：GetNo(e)
     * @param e
     * @return
     */
    public int getNo(E e) {
        int j = 0;
        DLinkNode<E> p = dhead.next;
        while (p != null && !p.data.equals(e)) {
            j++;
            p = p.next;
        }

        if (p == null) {
            return -1;
        } else {
            return j;
        }
    }

    /**
     * 将线性表种序号为 i 和 序号为 j的元素交换：swap(i,j)
     * @param i
     * @param j
     */
    public void swap(int i, int j) {
        if (i < 0 || i > size() - 1) {
            throw new IllegalArgumentException("交换：位置 i 不在有效的范围内。");
        }

        if (j < 0 || j > size() - 1) {
            throw new IllegalArgumentException("设置：位置 j 不在有效的范围内。");
        }
        DLinkNode<E> p = geti(i);
        DLinkNode<E> q = geti(j);
        E tmp = p.data;
        p.data = q.data;
        q.data = tmp;
    }

    /**
     * 将线性白哦转换为字符串：toString();
     * @return
     */
    public String toString() {
        StringBuilder ans = new StringBuilder();
        DLinkNode<E> p = dhead.next;
        while (p != null) {
            ans.append(p.data).append(" ");
            p = p.next;
        }

        return ans.toString();
    }


}
